package org.edu.modules.act.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.edu.modules.act.entity.ActReModelEntity;
import org.edu.modules.act.entity.ActReWordModel;
import org.edu.modules.act.mapper.ActReModelMapper;
import org.edu.modules.act.mapper.ActReWordModelMapper;
import org.edu.modules.act.service.ModelService;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 模型信息的业务逻辑实现层
 *
 * @版权所有 福州土著人信息科技有限公司
 */
@Service
@Transactional
public class ModelServiceImpl implements ModelService, ModelDataJsonConstants {

	@Autowired
	private ObjectMapper objectMapper;

	@Autowired
	private RepositoryService repositoryService;

	@Resource
	private ActReWordModelMapper actReWordModelMapper;

	@Resource
	private ActReModelMapper actReModelMapper;

	/**
	 * 查询模型分页
	 */
	@Override
	public LinkedHashMap<String, Object> queryModel(Integer currentPage, Integer pageSize, String name) {

		ModelQuery modelQuery = repositoryService.createModelQuery();
		if (StringUtils.isNotBlank(name)) {
			modelQuery.modelNameLike("%" + name + "%");
		}
		List<Model> resultList = modelQuery.orderByCreateTime().desc().listPage(pageSize * (currentPage - 1), pageSize);
		LinkedHashMap<String, Object> resultMap = new LinkedHashMap<>();
		resultMap.put("list", resultList);
		LinkedHashMap<String, Long> paginationMap = new LinkedHashMap<>();
		paginationMap.put("total", modelQuery.count());
		paginationMap.put("pageSize", (long) pageSize);
		paginationMap.put("current", (long) currentPage);
		resultMap.put("pagination", paginationMap);
		return resultMap;
	}

	/**
	 * 新增模型
	 */
	@Override
	public void addModel(String name, String category, String description) {
		Model model = repositoryService.newModel();
		int modelRevision = 1;
		String key = UUID.randomUUID().toString().replace("-", "");
		ObjectNode modelNode = objectMapper.createObjectNode();
		modelNode.put(MODEL_NAME, name);
		modelNode.put(MODEL_DESCRIPTION, description);
		modelNode.put(MODEL_REVISION, modelRevision);
		model.setName(name);
		model.setCategory(category);
		model.setKey(key);
		model.setMetaInfo(modelNode.toString());
		repositoryService.saveModel(model);
	}

	/**
	 * 编辑模型
	 */
	@Override
	public void updateModel(String modelId, String name, String category) throws IOException {
		Model model = repositoryService.getModel(modelId);
		ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
		modelJson.put(MODEL_NAME, name);
		model.setMetaInfo(modelJson.toString());
		model.setName(name);
		model.setCategory(category);
		repositoryService.saveModel(model);
	}

	/**
	 * 部署模型
	 */
	@Override
	public void deployModel(String modelId) throws IOException, XMLStreamException {

		Model model = repositoryService.getModel(modelId);
		byte[] bytes = repositoryService.getModelEditorSource(model.getId());

		//判断流程设计是否为空
		if (bytes == null) {
			throw new ActivitiException("模型数据为空，请先设计流程再上线");
		}
		//判断word模板是否上传
		QueryWrapper<ActReWordModel> wrapper = new QueryWrapper();
		//条件为表中MODEL_ID_等于参数modelId
		wrapper.eq("MODEL_ID",modelId);
		//模板表中对应当前的ModelId是否存在
		Integer count = actReWordModelMapper.selectCount(wrapper);

		if(count==0){
			throw new ActivitiException("word模型为空，请先上传word模型再上线");
		}

		InputStream xmlInputStream = new ByteArrayInputStream(bytes);
		XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
		xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
		xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
		InputStreamReader xmlInputStreamReader = new InputStreamReader(xmlInputStream, StandardCharsets.UTF_8);
		XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(xmlInputStreamReader);
		BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xmlStreamReader);
		if (bpmnModel.getProcesses().isEmpty()) {
			throw new ActivitiException("模型数据不符要求，请至少设计一条主线流程");
		}
		byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
		String processName = model.getName() + ".bpmn20.xml";
		Deployment deployment = repositoryService.createDeployment().name(model.getName()).addString(processName, new String(bpmnBytes, StandardCharsets.UTF_8)).category(model.getCategory())
				.deploy();
		model.setDeploymentId(deployment.getId());
		repositoryService.saveModel(model);
		xmlStreamReader.close();
		xmlInputStreamReader.close();
		xmlInputStream.close();

		//修改word模板的文件的流程部署ID
		ActReWordModel actReWordModel=new ActReWordModel();
		actReWordModel.setDeploymentId(deployment.getId());
		actReWordModelMapper.update(actReWordModel, wrapper);

	}

	/**
	 * 获取模型分类的集合
	 */
	@Override
	public Map<String, Object> getModelType() {
		Map<String, Object> map=new HashMap<>();
		QueryWrapper<ActReModelEntity> wrapper = new QueryWrapper();
		wrapper.select("CATEGORY_");
		wrapper.groupBy("CATEGORY_");
		List<ActReModelEntity> list = actReModelMapper.selectList(wrapper);
		map.put("modelType",list);
		return map;
	}

	/**
	 * 删除模型，并删除该模型所生成的流程部署、流程定义
	 */
	@Override
	public void deleteModel(String[] modelId) {
		for (int i = 0; i < modelId.length; i++) {
			Model model = repositoryService.getModel(modelId[i]);

			String deploymentId = model.getDeploymentId();

			if(deploymentId!=null){
				repositoryService.deleteDeployment(deploymentId, true);// true指级联删除
			}

			repositoryService.deleteModel(modelId[i]);
		}
	}

}
